/*
poll_case01的优化版本
    这个代码做了以下几点优化：

    1. 使用 `std::vector` 动态管理 `pollfd` 结构体和客户端套接字。
    2. 在每次迭代后，重新构造一个包含活跃连接的 `pollfd` 数组，以便移除已经关闭的客户端套接字。
    3. 使用 `recv` 代替 `read` 来接收数据，这是因为 `recv` 更适合用于套接字，并且可以在客户端断开连接时返回 0。
    4. 添加了错误处理来处理 `accept` 和 `recv` 失败的情况。
    5. 注释掉了设置非阻塞套接字的代码，因为在这个例子中我们不需要非阻塞行为。但是，如果你想要服务器能够同时处理多个操作（例如同时接受新的连接和读取数据），你可以取消注释这些行。
    6. 使用 `std::vector::swap` 来高效地交换旧的和新的 `pollfd` 数组，避免了不必要的拷贝。

    请注意，这个代码示例还没有处理所有可能的错误情况，例如 `accept` 可能因为各种原因（如资源限制）而失败。
    在生产环境中，你应该添加更详细的错误处理代码来确保服务器的健壮性。
*/

#include <iostream>  
#include <sys/poll.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <string.h>  
#include <unistd.h>  
#include <vector>  
#include <algorithm>  

const int PORT = 8080;  
  
int main() {  
    int master_socket, client_socket, activity;  
    struct sockaddr_in address;  
    std::vector<struct pollfd> fds;  
    std::vector<int> clients;  
  
    // 创建 socket  
    if ((master_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {  
        perror("socket failed");  
        exit(EXIT_FAILURE);  
    }  
  
    // 设置套接字为非阻塞（可选）  
    // int flags = fcntl(master_socket, F_GETFL, 0);  
    // fcntl(master_socket, F_SETFL, flags | O_NONBLOCK);  
  
    // 绑定到端口 8080  
    address.sin_family = AF_INET;  
    address.sin_addr.s_addr = INADDR_ANY;  
    address.sin_port = htons(PORT);  
  
    if (bind(master_socket, (struct sockaddr*)&address, sizeof(address)) < 0) {  
        perror("bind failed");  
        exit(EXIT_FAILURE);  
    }  
  
    // 监听  
    if (listen(master_socket, SOMAXCONN) < 0) {  
        perror("listen");  
        exit(EXIT_FAILURE);  
    }  
  
    // 添加主 socket 到 poll 数组  
    struct pollfd master_fd = {master_socket, POLLIN, 0};  
    fds.push_back(master_fd);  
  
    while (true) {  
        // 使用当前的文件描述符数量  
        activity = poll(fds.data(), fds.size(), -1);  
  
        if (activity < 0) {  
            if (errno != EINTR) {  
                perror("poll error");  
                break; // 或者选择其他适当的错误处理  
            }  
            continue;  
        }  
  
        // 遍历所有文件描述符  
        std::vector<struct pollfd> new_fds;  
        for (auto &fd : fds) {  
            if (fd.revents & POLLIN) {  
                // 检查是否有新连接  
                if (fd.fd == master_socket) { 
                    new_fds.push_back(master_fd); 

                    socklen_t addrlen = sizeof(address);  
                    client_socket = accept(master_socket, (struct sockaddr*)&address, &addrlen);  
  
                    if (client_socket < 0) {  
                        perror("accept failed");  
                        continue;  
                    }  
  
                    std::cout << "New connection accepted, client_socket: " << client_socket << std::endl;  
  
                    // 添加新 socket 到 poll 数组  
                    struct pollfd client_fd = {client_socket, POLLIN, 0};  
                    new_fds.push_back(client_fd);  
                    clients.push_back(client_socket);  
  
                } else {  
                    // 检查客户端数据  
                    char buffer[1024] = {0};  
                    ssize_t valread = recv(fd.fd, buffer, sizeof(buffer) - 1, 0);  
  
                    if (valread > 0) {  
                        // 接收客户端数据  
                        buffer[valread] = '\0';  
                        std::cout << "Received from client " << fd.fd << ": " << buffer << std::endl;  
                        new_fds.push_back(fd); // 保留现有连接  
                    } else if (valread == 0) {  
                        // 客户端断开连接  
                        std::cout << "Client " << fd.fd << " disconnected" << std::endl;  
                        close(fd.fd);  
                    } else {  
                        // 读取出错  
                        perror("recv failed");  
                        close(fd.fd);  
                    }  
                }  
            } else {  
                // 没有事件发生，保留在监听列表中  
                new_fds.push_back(fd);  
            }  
        }  
  
        // 交换 poll 数组  
        fds.swap(new_fds);  
    }  
  
    // 关闭主套接字（可选，通常会在退出前自动关闭）  
    close(master_socket);  
  
    return 0;  
}